home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / rcm / rcm_misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-05-04  |  11.8 KB  |  507 lines

  1. /*
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This is a plug-in for the GIMP.
  5.  *
  6.  * Colormap-Rotation plug-in. Exchanges two color ranges.
  7.  *
  8.  * Copyright (C) 1999 Sven Anders (anderss@fmi.uni-passau.de)
  9.  *                    Based on code from Pavel Grinfeld (pavel@ml.com)
  10.  *
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  25.  */
  26.  
  27. /*-----------------------------------------------------------------------------------
  28.  * Change log:
  29.  * 
  30.  * Version 2.0, 04 April 1999.
  31.  *  Nearly complete rewrite, made plug-in stable.
  32.  *  (Works with GIMP 1.1 and GTK+ 1.2)
  33.  *
  34.  * Version 1.0, 27 March 1997.
  35.  *  Initial (unstable) release by Pavel Grinfeld
  36.  *
  37.  *-----------------------------------------------------------------------------------*/
  38.  
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <math.h>
  42.  
  43. #include <gtk/gtk.h>
  44. #include <libgimp/gimp.h>
  45.  
  46. #include "rcm.h"
  47. #include "rcm_misc.h"
  48. #include "rcm_gdk.h"
  49.  
  50. /*-----------------------------------------------------------------------------------*/
  51.  
  52. float 
  53. arctg (float y, 
  54.        float x)
  55. {
  56.   float temp = atan2(y,x);
  57.   return (temp<0) ? (temp+TP) : temp;
  58. }
  59.  
  60. inline 
  61. float sign (float x)
  62. {
  63.   return (x<0)?(-1):(1);
  64. }
  65.  
  66. /*-----------------------------------------------------------------------------------*/
  67.  
  68. float 
  69. min_prox (float alpha, 
  70.       float beta, 
  71.       float angle)
  72. {
  73.   gfloat temp1 = MIN(angle_mod_2PI(alpha - angle),
  74.            TP-angle_mod_2PI(alpha - angle));
  75.   gfloat temp2 = MIN(angle_mod_2PI(beta - angle),
  76.            TP-angle_mod_2PI(beta - angle));
  77.  
  78.   return MIN(temp1, temp2);
  79. }
  80.  
  81. float*
  82. closest (float *alpha, 
  83.      float *beta, 
  84.      float  angle)
  85. {
  86.   float temp_alpha = MIN(angle_mod_2PI(*alpha-angle),
  87.              TP-angle_mod_2PI(*alpha-angle));
  88.  
  89.   float temp_beta  = MIN(angle_mod_2PI(*beta -angle),
  90.              TP-angle_mod_2PI(*beta -angle));
  91.  
  92.   if (temp_alpha-temp_beta<0) 
  93.     return alpha;
  94.   else 
  95.     return beta;
  96. }
  97.  
  98. float 
  99. angle_mod_2PI (float angle)
  100. {
  101.   if (angle < 0) 
  102.     return angle + TP;
  103.   else if (angle > TP)
  104.     return angle - TP;
  105.   else
  106.     return angle;
  107. }
  108.  
  109. /*-----------------------------------------------------------------------------------*/
  110. /* supporting routines  */
  111. /*-----------------------------------------------------------------------------------*/
  112.  
  113. float 
  114. rcm_linear (float A, 
  115.         float B, 
  116.         float C, 
  117.         float D, 
  118.         float x)
  119. {
  120.   if (B > A)
  121.     if (A<=x && x<=B)
  122.       return C+(D-C)/(B-A)*(x-A);
  123.     else if (A<=x+TP && x+TP<=B)
  124.       return C+(D-C)/(B-A)*(x+TP-A);    
  125.     else
  126.       return x;
  127.   else 
  128.     if (B<=x && x<=A)
  129.       return C+(D-C)/(B-A)*(x-A);
  130.     else if (B<=x+TP && x+TP<=A)
  131.       return C+(D-C)/(B-A)*(x+TP-A);    
  132.     else
  133.       return x;
  134. }
  135.  
  136. float 
  137. rcm_left_end (RcmAngle *angle)
  138. {
  139.   gfloat alpha  = angle->alpha;
  140.   gfloat beta   = angle->beta;
  141.   gint   cw_ccw = angle->cw_ccw;
  142.   
  143.   switch (cw_ccw)
  144.   {
  145.     case (-1): if (alpha < beta) return alpha + TP;
  146.     default: return alpha; /* 1 */
  147.   }
  148. }
  149.  
  150. float 
  151. rcm_right_end (RcmAngle *angle)
  152. {
  153.   gfloat alpha  = angle->alpha;
  154.   gfloat beta   = angle->beta;
  155.   gint   cw_ccw = angle->cw_ccw;
  156.   
  157.   switch (cw_ccw)
  158.   {
  159.     case 1: if (beta < alpha) return beta + TP;
  160.     default: return beta; /* -1 */
  161.   }
  162. }
  163.  
  164. float 
  165. rcm_angle_inside_slice (float     angle, 
  166.             RcmAngle *slice)
  167. {
  168.   return angle_mod_2PI(slice->cw_ccw * (slice->beta-angle)) /
  169.          angle_mod_2PI(slice->cw_ccw * (slice->beta-slice->alpha));
  170. }
  171.  
  172. gint 
  173. rcm_is_gray (float s)
  174. {
  175.   if (s <= Current.Gray->gray_sat) return 1;
  176.   return 0;
  177. }
  178.  
  179. /*-----------------------------------------------------------------------------------*/
  180. /* reduce image/selection for preview */
  181. /*-----------------------------------------------------------------------------------*/
  182.  
  183. ReducedImage*
  184. rcm_reduce_image (GimpDrawable *drawable, 
  185.           GimpDrawable *mask, 
  186.           gint          LongerSize, 
  187.           gint          Slctn)
  188. {
  189.   guint32 gimage;
  190.   GimpPixelRgn srcPR, srcMask;
  191.   ReducedImage *temp;
  192.   guchar *tempRGB, *src_row, *tempmask, *src_mask_row;
  193.   gint i, j, whichcol, whichrow, x1, x2, y1, y2;
  194.   gint RH, RW, width, height, bytes;
  195.   gint NoSelectionMade;
  196.   gint offx, offy;
  197.   gdouble *tempHSV, H, S, V;
  198.  
  199.   temp = g_new0 (ReducedImage, 1);
  200.  
  201.   bytes = drawable->bpp;  
  202.  
  203.   /* get bounds of image or selection */
  204.  
  205.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  206.  
  207.   if (((x2-x1) != drawable->width) || ((y2-y1) != drawable->height)) 
  208.     NoSelectionMade = FALSE;
  209.   else
  210.     NoSelectionMade = TRUE;
  211.  
  212.   switch (Slctn)
  213.   {
  214.     case ENTIRE_IMAGE:
  215.       x1 = 0;
  216.       x2 = drawable->width;
  217.       y1 = 0;
  218.       y2 = drawable->height;
  219.       break;  
  220.  
  221.     case SELECTION_IN_CONTEXT:
  222.       x1 = MAX (0, x1 - (x2-x1) / 2.0);
  223.       x2 = MIN (drawable->width, x2 + (x2-x1) / 2.0);
  224.       y1 = MAX (0, y1 - (y2-y1) / 2.0);
  225.       y2 = MIN (drawable->height, y2 + (y2-y1) / 2.0);
  226.       break;  
  227.  
  228.     default:
  229.       break; /* take selection dimensions */
  230.   }
  231.  
  232.   /* clamp to image size since this is the size of the mask */
  233.  
  234.   gimp_drawable_offsets (drawable->id, &offx, &offy);
  235.   gimage = gimp_drawable_image (drawable->id);
  236.  
  237.   x1 = CLAMP (x1, - offx, gimp_image_width (gimage) - offx);
  238.   x2 = CLAMP (x2, - offx, gimp_image_width (gimage) - offx);
  239.   y1 = CLAMP (y1, - offy, gimp_image_height (gimage) - offy);
  240.   y2 = CLAMP (y2, - offy, gimp_image_height (gimage) - offy);
  241.  
  242.   /* calculate size of preview */
  243.   
  244.   width  = x2 - x1;
  245.   height = y2 - y1;
  246.  
  247.   if (width < 1 || height < 1)
  248.     return temp;
  249.  
  250.   if (width > height)
  251.   {
  252.     RW = LongerSize;
  253.     RH = (float) height * (float) LongerSize / (float) width;
  254.   }
  255.   else
  256.   {
  257.     RH = LongerSize;
  258.     RW = (float)width * (float) LongerSize / (float) height;
  259.   }
  260.  
  261.   /* allocate memory */
  262.   
  263.   tempRGB  = g_new (guchar, RW * RH * bytes);
  264.   tempHSV  = g_new (gdouble, RW * RH * bytes);
  265.   tempmask = g_new (guchar, RW * RH);
  266.  
  267.   gimp_pixel_rgn_init(&srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
  268.   gimp_pixel_rgn_init(&srcMask, mask, 
  269.                       x1 + offx, y1 + offy, width, height, FALSE, FALSE);
  270.  
  271.   src_row = g_new (guchar, width * bytes);
  272.   src_mask_row = g_new (guchar, width * bytes);
  273.  
  274.   /* reduce image */
  275.  
  276.   for (i=0; i<RH; i++)
  277.   {
  278.     whichrow = (float)i * (float)height / (float)RH;
  279.     gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1 + whichrow, width);   
  280.     gimp_pixel_rgn_get_row (&srcMask, src_mask_row, 
  281.                             x1 + offx, y1 + offy + whichrow, width);
  282.    
  283.     for (j=0; j<RW; j++)
  284.     {
  285.       whichcol = (float)j * (float)width / (float)RW;
  286.  
  287.       if (NoSelectionMade)
  288.     tempmask[i*RW+j] = 255;
  289.       else
  290.     tempmask[i*RW+j] = src_mask_row[whichcol];
  291.       
  292.       gimp_rgb_to_hsv4 (&src_row[whichcol*bytes], &H, &S, &V);
  293.  
  294.       tempRGB[i*RW*bytes+j*bytes+0] = src_row[whichcol*bytes+0];
  295.       tempRGB[i*RW*bytes+j*bytes+1] = src_row[whichcol*bytes+1];
  296.       tempRGB[i*RW*bytes+j*bytes+2] = src_row[whichcol*bytes+2];
  297.  
  298.       tempHSV[i*RW*bytes+j*bytes+0] = H;
  299.       tempHSV[i*RW*bytes+j*bytes+1] = S;
  300.       tempHSV[i*RW*bytes+j*bytes+2] = V;
  301.  
  302.       if (bytes == 4)
  303.     tempRGB[i*RW*bytes+j*bytes+3] = src_row[whichcol*bytes+3];
  304.  
  305.     } /* for j */
  306.   } /* for i */
  307.  
  308.   /* return values */
  309.  
  310.   temp->width = RW;
  311.   temp->height = RH;
  312.   temp->rgb = tempRGB;
  313.   temp->hsv = tempHSV;
  314.   temp->mask = tempmask;  
  315.  
  316.   return temp;
  317. }
  318.  
  319. /*-----------------------------------------------------------------------------------*/
  320. /* render before/after preview */
  321. /*-----------------------------------------------------------------------------------*/
  322.  
  323. static gint 
  324. rcm_fake_transparency (gint i, 
  325.                gint j)
  326. {
  327.   if ( ((i%20)-10)*((j%20)-10) > 0 ) 
  328.     return 102;
  329.  
  330.   return 153;
  331. }
  332.  
  333. void 
  334. rcm_render_preview (GtkWidget *preview, 
  335.             gint       version)
  336.   ReducedImage *reduced;
  337.   gint RW, RH, bytes, i, j, k, unchanged, skip;
  338.   guchar *rgb_array, *a;
  339.   gdouble H, S, V;
  340.   gdouble *hsv_array;
  341.   guchar rgb[3];
  342.   float degree, transp;
  343.  
  344.   /* init some variables */
  345.  
  346.   g_return_if_fail (preview != NULL);
  347.  
  348.   reduced = Current.reduced;
  349.   RW = reduced->width;
  350.   RH = reduced->height;
  351.   bytes = Current.drawable->bpp;
  352.   hsv_array = reduced->hsv;
  353.   rgb_array = reduced->rgb;
  354.  
  355.   a = g_new (guchar, bytes * RW);
  356.   
  357.   if (version == CURRENT) 
  358.   {
  359.     for (i=0; i<RH; i++)
  360.     {
  361.       for (j=0; j<RW; j++)
  362.       {
  363.     unchanged = 1; /* TRUE */
  364.     skip = 0; /* FALSE */
  365.     
  366.     H = hsv_array[i*RW*bytes + j*bytes + 0];
  367.     S = hsv_array[i*RW*bytes + j*bytes + 1];
  368.     V = hsv_array[i*RW*bytes + j*bytes + 2];
  369.     
  370.     if (rcm_is_gray(S) && (reduced->mask[i*RW+j] != 0))
  371.     {
  372.       switch (Current.Gray_to_from)
  373.       {
  374.         case GRAY_FROM:
  375.           if (rcm_angle_inside_slice(Current.Gray->hue, Current.From->angle) <= 1) 
  376.           {
  377.         H = Current.Gray->hue/TP;
  378.         S = Current.Gray->satur;
  379.           }
  380.           else 
  381.         skip = 1;
  382.           break;
  383.         
  384.         case GRAY_TO:  
  385.           unchanged = 0; 
  386.           skip = 1;
  387.           gimp_hsv_to_rgb4 (rgb, Current.Gray->hue/TP, Current.Gray->satur, V);
  388.         break;
  389.         
  390.         default: break;
  391.       } /* switch */
  392.     } /* if */
  393.  
  394.     if (!skip)
  395.     {
  396.       unchanged = 0;
  397.       H = rcm_linear(rcm_left_end(Current.From->angle),
  398.              rcm_right_end(Current.From->angle),
  399.              rcm_left_end(Current.To->angle),
  400.              rcm_right_end(Current.To->angle),
  401.              H*TP);    
  402.  
  403.       H = angle_mod_2PI(H) / TP;
  404.       gimp_hsv_to_rgb4 (rgb, H,S,V);
  405.     } /* if (!skip) */
  406.     
  407.     if (unchanged)degree = 0;
  408.     else
  409.       degree = reduced->mask[i*RW+j] / 255.0;
  410.     
  411.     a[j*3+0] = (1-degree) * rgb_array[i*RW*bytes + j*bytes + 0] + degree * rgb[0];
  412.     a[j*3+1] = (1-degree) * rgb_array[i*RW*bytes + j*bytes + 1] + degree * rgb[1];
  413.     a[j*3+2] = (1-degree) * rgb_array[i*RW*bytes + j*bytes + 2] + degree * rgb[2];
  414.     
  415.     /* apply transparency */
  416.     if (bytes == 4) 
  417.     {
  418.       for (k=0; k<3; k++)
  419.       {
  420.         /*        transp = reduced->mask[i*RW*bytes+j*bytes+3] / 255.0; */
  421.         transp = rgb_array[i*RW*bytes+j*bytes+3] / 255.0;
  422.         a[3*j+k] = transp * a[3*j+k] + (1-transp) * rcm_fake_transparency(i,j);
  423.       }
  424.  
  425.     } /* if */
  426.  
  427.       } /* for j */
  428.  
  429.       gtk_preview_draw_row(GTK_PREVIEW(preview), a, 0, i, RW);
  430.  
  431.     } /* for i */
  432.   }
  433.   else /* ORIGINAL */
  434.   {
  435.     for (i=0; i<RH; i++)
  436.     {
  437.       for (j=0; j<RW; j++)
  438.       {
  439.     a[j*3+0] = rgb_array[i*RW*bytes + j*bytes + 0];
  440.     a[j*3+1] = rgb_array[i*RW*bytes + j*bytes + 1];
  441.     a[j*3+2] = rgb_array[i*RW*bytes + j*bytes + 2];
  442.       
  443.     if (bytes == 4) 
  444.     {
  445.       for (k=0; k<3; k++)
  446.       {
  447.         transp = rgb_array[i*RW*bytes+j*bytes+3] / 255.0;
  448.         a[3*j+k] = transp * a[3*j+k] + (1-transp) * rcm_fake_transparency(i,j);
  449.       }
  450.     } /* if */
  451.  
  452.       } /* for j */
  453.  
  454.       gtk_preview_draw_row(GTK_PREVIEW(preview), a, 0, i, RW);
  455.  
  456.     } /* for i */
  457.   }
  458.  
  459.   g_free (a); 
  460.   gtk_widget_draw(preview, NULL);
  461.   gdk_flush();
  462. }
  463.  
  464. /*-----------------------------------------------------------------------------------*/
  465. /* render circle */
  466. /*-----------------------------------------------------------------------------------*/
  467.  
  468. void 
  469. rcm_render_circle (GtkWidget *preview, 
  470.            int        sum, 
  471.            int        margin)
  472.   gint i, j;
  473.   gdouble h, s, v;
  474.   guchar *a;
  475.  
  476.   a = g_new (guchar, 3*sum);
  477.   
  478.   if (preview == NULL) return;
  479.   
  480.   for (j = 0; j < sum; j++)
  481.   {
  482.     for (i = 0; i < sum; i++)
  483.     {
  484.       s = sqrt ((SQR (i - sum / 2.0) + SQR (j - sum / 2.0)) / (float) SQR (sum / 2.0 - margin));
  485.       if (s > 1)
  486.       {
  487.     a[i*3+0] = 255;
  488.     a[i*3+1] = 255;
  489.     a[i*3+2] = 255;
  490.       }
  491.       else
  492.       {
  493.     h = arctg (sum / 2.0 - j, i - sum / 2.0) / (2 * G_PI);
  494.     v = 1 - sqrt (s) / 4;
  495.     gimp_hsv_to_rgb4 (&a[i*3], h, s, v);
  496.       }    
  497.     }   
  498.     gtk_preview_draw_row(GTK_PREVIEW(preview), a, 0, j, sum);
  499.   }
  500.   
  501.   g_free (a); 
  502.   gtk_widget_draw (preview, NULL);
  503.   gdk_flush ();
  504. }
  505.